package loads

import (
    "jvmgo/ch10/instructions/base"
    "jvmgo/ch10/rtda"
    "jvmgo/ch10/rtda/heap"
)

// 从数组中加载引用到操作数栈
type AALOAD struct {
    base.NoOperandsInstruction
}

func (self *AALOAD) Execute(frame *rtda.Frame) {
    stack := frame.OperandStack()
    index := stack.PopInt()
    arrRef := stack.PopRef()

    checkNotNil(arrRef)
    refs := arrRef.Refs()
    checkIndex(len(refs), index)
    stack.PushRef(refs[index])
}

// 从数组中加载byte或者boolean到操作数栈
type BALOAD struct {
    base.NoOperandsInstruction
}

func (self *BALOAD) Execute(frame *rtda.Frame) {
    stack := frame.OperandStack()
    index := stack.PopInt()
    arrRef := stack.PopRef()

    checkNotNil(arrRef)
    bytes := arrRef.Bytes()
    checkIndex(len(bytes), index)
    stack.PushInt(int32(bytes[index]))
}

// 从数组中加载char到操作数栈
type CALOAD struct {
    base.NoOperandsInstruction
}

func (self *CALOAD) Execute(frame *rtda.Frame) {
    stack := frame.OperandStack()
    index := stack.PopInt()
    arrRef := stack.PopRef()

    checkNotNil(arrRef)
    chars := arrRef.Chars()
    checkIndex(len(chars), index)
    stack.PushInt(int32(chars[index]))
}

// 从数组中加载double到操作数栈
type DALOAD struct {
    base.NoOperandsInstruction
}

func (self *DALOAD) Execute(frame *rtda.Frame) {
    stack := frame.OperandStack()
    index := stack.PopInt()
    arrRef := stack.PopRef()

    checkNotNil(arrRef)
    doubles := arrRef.Doubles()
    checkIndex(len(doubles), index)
    stack.PushDouble(doubles[index])
}

// 从数组中加载float到操作数栈
type FALOAD struct {
    base.NoOperandsInstruction
}

func (self *FALOAD) Execute(frame *rtda.Frame) {
    stack := frame.OperandStack()
    index := stack.PopInt()
    arrRef := stack.PopRef()

    checkNotNil(arrRef)
    floats := arrRef.Floats()
    checkIndex(len(floats), index)
    stack.PushFloat(floats[index])
}

// 从数组中加载int到操作数栈
type IALOAD struct {
    base.NoOperandsInstruction
}

func (self *IALOAD) Execute(frame *rtda.Frame) {
    stack := frame.OperandStack()
    index := stack.PopInt()
    arrRef := stack.PopRef()

    checkNotNil(arrRef)
    ints := arrRef.Ints()
    checkIndex(len(ints), index)
    stack.PushInt(ints[index])
}

// 从数组中加载long到操作数栈
type LALOAD struct {
    base.NoOperandsInstruction
}

func (self *LALOAD) Execute(frame *rtda.Frame) {
    stack := frame.OperandStack()
    index := stack.PopInt()
    arrRef := stack.PopRef()

    checkNotNil(arrRef)
    longs := arrRef.Longs()
    checkIndex(len(longs), index)
    stack.PushLong(longs[index])
}

// 从数组中加载short到操作数栈
type SALOAD struct {
    base.NoOperandsInstruction
}

func (self *SALOAD) Execute(frame *rtda.Frame) {
    stack := frame.OperandStack()
    index := stack.PopInt()
    arrRef := stack.PopRef()

    checkNotNil(arrRef)
    shorts := arrRef.Shorts()
    checkIndex(len(shorts), index)
    stack.PushInt(int32(shorts[index]))
}

//检查数组引用是否为空
func checkNotNil(ref *heap.Object) {
    if ref == nil {
        panic("java.lang.NullPointerException")
    }
}

//检查数组越界
func checkIndex(arrLen int, index int32) {
    if index < 0 || index >= int32(arrLen) {
        panic("ArrayIndexOutOfBoundsException")
    }
}